/**
 * Copyright 2018-2019 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.support.refresh;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.jianggujin.modulelink.util.JAssert;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JThreadFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;

/**
 * 带有刷新计划的刷新模块的抽象实现
 * 
 * @author jianggujin
 *
 */
public class JModuleRefreshScheduler {

    private final JLog logger = JLogFactory.getLog(JModuleRefreshScheduler.class);
    /**
     * 默认延迟执行,单位秒
     */
    private static final int DEFAULT_INITIAL_DELAY = 5;

    /**
     * 模块刷新默认间隔,单位秒
     */
    private static final int DEFAULT_REFRESH_DELAY = 60;

    /** 初始化的延迟时间 */
    private int initialDelay = DEFAULT_INITIAL_DELAY;

    /** 刷新间隔时间 */
    private int refreshDelay = DEFAULT_REFRESH_DELAY;

    private ScheduledExecutorService scheduledExecutor;
    private final JModuleRefresh moduleRefresh;
    private AtomicBoolean started = new AtomicBoolean(false);

    private Runnable runnable = new Runnable() {

        @Override
        public void run() {
            JModuleRefreshScheduler.this.run();
        }
    };

    public JModuleRefreshScheduler(JModuleRefresh moduleRefresh) {
        JAssert.checkNotNull(moduleRefresh, "moduleRefresh must not be null");
        this.moduleRefresh = moduleRefresh;
    }

    /**
     * 初始化ScheduledExecutor，启动定时任务
     * 
     * @throws Exception 启动定时任务异常
     */
    public synchronized void start() throws Exception {
        JAssert.checkState(started.compareAndSet(false, true), "scheduler already started.");
        // 先刷新一次
        moduleRefresh.refreshModuleConfigs();
        scheduledExecutor = Executors
                .newSingleThreadScheduledExecutor(new JThreadFactory("JModuleLink_refresh-schedule-"));
        scheduledExecutor.scheduleWithFixedDelay(runnable, initialDelay, refreshDelay, TimeUnit.SECONDS);
        if (logger.isInfoEnabled()) {
            logger.info("scheduler start");
        }
    }

    private void run() {
        try {
            if (logger.isInfoEnabled()) {
                logger.info("Start Module refresh");
            }
            moduleRefresh.refreshModuleConfigs();
            if (logger.isInfoEnabled()) {
                logger.info("Stop Module refresh");
            }
        } catch (Throwable e) {
            logger.error("Failed to refresh Module", e);
        }
    }

    /**
     * 关闭ScheduledExecutor
     * 
     * @throws Exception 关闭ScheduledExecutor出现异常
     */
    public synchronized void destroy() throws Exception {
        started.set(false);
        if (scheduledExecutor != null) {
            scheduledExecutor.shutdownNow();
        }
        scheduledExecutor = null;
    }

    /**
     * 设置初始化的延迟时间
     * 
     * @param initialDelay 初始化的延迟时间
     */
    public void setInitialDelay(int initialDelay) {
        this.initialDelay = initialDelay;
    }

    /**
     * 设置刷新间隔时间
     * 
     * @param refreshDelay 刷新间隔时间
     */
    public void setRefreshDelay(int refreshDelay) {
        this.refreshDelay = refreshDelay;
    }

    /**
     * 是否已启动调度
     * 
     * @return 已启动调度则返回true
     */
    public boolean isStart() {
        return started.get();
    }
}
